﻿<ComClass(ClsTriangle.ClassId, ClsTriangle.InterfaceId, ClsTriangle.EventsId)>
Public Class ClsTriangle

#Region "COM GUID"
    ' 这些 GUID 提供此类的 COM 标识 
    ' 及其 COM 接口。若更改它们，则现有的
    ' 客户端将不再能访问此类。
    Public Const ClassId As String = "b1fee6b8-fa8d-4a9a-9a92-0a81c1827d41"
    Public Const InterfaceId As String = "5ebd5a25-660a-4294-baaa-bcc7027ee66e"
    Public Const EventsId As String = "b48880b5-3f4f-4ccd-875d-a63aa1cb5ebd"
#End Region

    ' 可创建的 COM 类必须具有一个不带参数的 Public Sub New() 
    ' 否则， 将不会在 
    ' COM 注册表中注册此类，且无法通过
    ' CreateObject 创建此类。
    Public Sub New()
        MyBase.New()
    End Sub

#Region "字段和属性"
    Private _ptA As ClsPoint2d
    Public Property PointA() As ClsPoint2d
        Get
            Return _ptA
        End Get
        Set(ByVal value As ClsPoint2d)
            _ptA = value
        End Set
    End Property
    Private _ptB As ClsPoint2d
    Public Property PointB() As ClsPoint2d
        Get
            Return _ptB
        End Get
        Set(ByVal value As ClsPoint2d)
            _ptB = value
        End Set
    End Property
    Private _ptC As ClsPoint2d
    Public Property PointC() As ClsPoint2d
        Get
            Return _ptC
        End Get
        Set(ByVal value As ClsPoint2d)
            _ptC = value
        End Set
    End Property

    ''' <summary>
    ''' 三角形面积
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property Area As Double
        Get
            Dim Vab = Me.PointA.GetVector2dTo(Me.PointB)
            Dim Vac = Me.PointA.GetVector2dTo(Me.PointC)
            Return 0.5 * Vab.CrossProductWith(Vac)
        End Get
    End Property

    ''' <summary>
    ''' 三角形周长
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property Perimeter As Double
        Get
            Dim Disab = Me.PointA.GetDistanceTo(Me.PointB)
            Dim Disac = Me.PointA.GetDistanceTo(Me.PointC)
            Dim Disbc = Me.PointB.GetDistanceTo(Me.PointC)
            Return Disab + Disac + Disbc
        End Get
    End Property

    ''' <summary>
    ''' 求三角形的类型'https://baike.baidu.com/item/%E4%B8%89%E8%A7%92%E5%BD%A2/179552
    ''' </summary>
    ''' <returns>三角形类型枚举</returns>
    Public ReadOnly Property TriangleType As 三角形类型
        Get
            Dim Disab = Me.PointA.GetDistanceTo(Me.PointB)
            Dim Disac = Me.PointA.GetDistanceTo(Me.PointC)
            Dim Disbc = Me.PointB.GetDistanceTo(Me.PointC)

            If Disab = Disac = Disbc Then
                Return 三角形类型.等边三角形
            Else
                Dim temps As New List(Of Double)
                temps.AddRange({Disab, Disac, Disbc})
                Dim max = temps.Max()
                temps.Remove(max)
                Dim checkItem = max * max - temps(0) * temps(0) + temps(1) * temps(1)
                If Math.Abs(checkItem) < 0.00000001 Then
                    If temps(0) = temps(1) Then
                        Return 三角形类型.直角等腰三角形
                    Else
                        Return 三角形类型.直角非等腰三角形
                    End If

                ElseIf checkItem > 0 Then
                    If Math.Abs(temps(0) - temps(1)) < 0.00000001 Then
                        Return 三角形类型.钝角等腰三角形
                    Else
                        Return 三角形类型.钝角非等腰三角形
                    End If
                Else
                    If Math.Abs(temps(0) - temps(1)) < 0.00000001 Then
                        Return 三角形类型.锐角等腰三角形
                    Else
                        Return 三角形类型.锐角非等腰三角形
                    End If
                End If

            End If
        End Get
    End Property

    ''' <summary>
    ''' 外心,外接圆的圆心
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property CircumcircleCenter As ClsPoint2d
        'https://blog.csdn.net/MallowFlower/article/details/79919797
        Get
            Dim x1 = Me.PointA.X
            Dim x2 = Me.PointB.X
            Dim x3 = Me.PointC.X
            Dim y1 = Me.PointA.Y
            Dim y2 = Me.PointB.Y
            Dim y3 = Me.PointC.Y
            Dim rtn As New ClsPoint2d With {
                .X = ((y2 - y1) * (y3 * y3 - y1 * y1 + x3 * x3 - x1 * x1) - (y3 - y1) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1)) / (2.0 * ((x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1))),
                .Y = ((x2 - x1) * (x3 * x3 - x1 * x1 + y3 * y3 - y1 * y1) - (x3 - x1) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1)) / (2.0 * ((y3 - y1) * (x2 - x1) - (y2 - y1) * (x3 - x1)))
            }
            Return rtn
        End Get
    End Property

    ''' <summary>
    '''外接圆半径：R=a * b * c / (4 * S),其中S是三角形面积，a、b、c是三角形三边。
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property CircumcircleRadius As Double
        '设三角形三边及其对角分别为a、b、c，∠A、∠B、∠C
        '正弦定理有 1) 2R=a/SinA=b/SinB=c/SinC(人教高中版)
        '由此可得：r=a/（2sinA）=b/（2sinB）=c/（2sinC）
        'r=abc/（4S△ABC）
        '三角形外心的向量关系
        '向量PA的模=向量PB的模=向量PC的模（ABC为三角形三个顶点，P为外心）
        Get
            Return 0.5 * SideA / Math.Sin(AngleA)
        End Get
    End Property

    ''' <summary>
    ''' 内心,内切圆的圆心坐标
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property InscribedCircleCenter As ClsPoint2d
        'https://www.3rxing.org/question/29dd82c0c583539533.html
        ' 设三角形三个顶点 A, B, C 的坐标为
        'A：(x1,x2)；B：(y1,y2)；C：(z1,z2)
        '且三边的长为：
        'BC = a；AC = b；AB = c 
        '(用勾股定理可求)
        '则该三角形【内切圆圆心】坐标为：
        '( [ax1+by1+cz1] / [a+b+c]， [ax2+by2+cz2] / [a+b+c]  )
        Get
            Dim rtn As New ClsPoint2d With {
                .X = (SideA * Me.PointA.X + SideB * Me.PointB.X + SideC * Me.PointC.X) / Me.Perimeter,
                .Y = (SideA * Me.PointA.Y + SideB * Me.PointB.Y + SideC * Me.PointC.Y) / Me.Perimeter
            }
            Return rtn
        End Get
    End Property
    ''' <summary>
    ''' 内切圆半径：r=2 * S / (a + b + c)，其中S是三角形面积，a、b、c是三角形三边。
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property InscribedCircleRadius As Double
        '直角三角形：内切圆半径为r=（a+b-c）/2 (a,b为直角边，c为斜边)
        '一般三角形的内切圆半径为r=2S/(a+b+c)，S是三角形的面积公式
        '(其中S=√p(p-a)(p-b)(p-c),p是半周长)
        Get
            Return 2.0 * Math.Abs(Me.Area) / (Me.Perimeter)
        End Get
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property GravityCenter As ClsPoint2d
        Get
            'https://www.cnblogs.com/7qin/p/10012868.html
            '已知三角形△A1A2A3的顶点坐标Ai ( xi , yi ) ( i =1, 2, 3) 。则它的重心坐标为
            'xg = (x1 + x2 + x3) / 3 ;
            'yg = (y1 + y2 + y3) / 3 ;
            Dim rtn As New ClsPoint2d With {
                .X = (Me.PointA.X + Me.PointB.X + Me.PointC.X) / 3.0,
                .Y = (Me.PointA.Y + Me.PointB.Y + Me.PointC.Y) / 3.0
            }
            Return rtn
        End Get
    End Property
    ''' <summary>
    '''三边高的交点,垂心
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property OrthoCenter As ClsPoint2d
        Get
            'https://blog.csdn.net/islittlehappy/article/details/81533090
            Dim A1 = Me.PointB.X - Me.PointC.X
            Dim B1 = Me.PointB.Y - Me.PointC.Y
            Dim C1 = A1 * Me.PointA.Y - B1 * Me.PointA.X

            Dim A2 = Me.PointA.X - Me.PointC.X
            Dim B2 = Me.PointA.Y - Me.PointC.Y
            Dim C2 = A2 * Me.PointB.Y - B2 * Me.PointB.X

            Dim rtn As New ClsPoint2d With {
               .X = (A1 * C2 - A2 * C1) / (A2 * B1 - A1 * B2),
               .Y = (B1 * C2 - B2 * C1) / (A2 * B1 - A1 * B2)
           }
            Return rtn

        End Get
    End Property


    Public ReadOnly Property SideA As Double

        Get
            Return Me.PointB.GetDistanceTo(Me.PointC)
        End Get
    End Property

    Public ReadOnly Property AngleA As Double
        Get
            Return Me.PointA.GetVector2dTo(Me.PointB).GetAngleTo(Me.PointA.GetVector2dTo(Me.PointC))

        End Get
    End Property
    Public ReadOnly Property SideB As Double

        Get
            Return Me.PointA.GetDistanceTo(Me.PointC)
        End Get
    End Property
    Public ReadOnly Property AngleB As Double
        Get
            Return Me.PointB.GetVector2dTo(Me.PointA).GetAngleTo(Me.PointB.GetVector2dTo(Me.PointC))

        End Get
    End Property
    Public ReadOnly Property SideC As Double

        Get
            Return Me.PointB.GetDistanceTo(Me.PointA)
        End Get
    End Property
    Public ReadOnly Property AngleC As Double
        Get
            Return Me.PointC.GetVector2dTo(Me.PointA).GetAngleTo(Me.PointC.GetVector2dTo(Me.PointB))

        End Get
    End Property

    Public ReadOnly Property IsClockWise() As Boolean
        Get
            Dim m As New ClsMath
            Return m.IsClockWise(Me.PointC, Me.PointA, Me.PointB) = 旋转方向.ClockWise
        End Get
    End Property
#End Region

#Region "构造函数"
    Public Sub CreatorByPoints(a As ClsPoint2d, b As ClsPoint2d, c As ClsPoint2d)
        Me.PointA = a
        Me.PointB = b
        Me.PointC = c
    End Sub

#End Region

#Region "旋转,移动,缩放,镜像"
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="angle"></param>
    ''' <param name="origin"></param>
    Public Sub RotateTo(angle As Double, origin As ClsPoint2d)
        Me.PointA.Rotate(angle, origin)
        Me.PointB.Rotate(angle, origin)
        Me.PointC.Rotate(angle, origin)
    End Sub

    ''' <summary>
    ''' 移动当前三角形
    ''' </summary>
    ''' <param name="Displacement">代表移动的向量</param>
    Public Sub MoveTo(Displacement As ClsVector2d)
        Me.PointA.MoveTo(Displacement)
        Me.PointB.MoveTo(Displacement)
        Me.PointC.MoveTo(Displacement)
    End Sub

    ''' <summary>
    ''' 缩放当前三角形获取新的三角形
    ''' </summary>
    ''' <param name="scaleFactor">缩放的系数，大于1表示放大，小于1表示缩小</param>
    ''' <param name="scaleCenter">缩放的基准点</param>
    ''' <returns>新的点 </returns>
    Public Function Scaling(ByVal scaleFactor As Double, ByVal scaleCenter As ClsPoint2d) As ClsTriangle
        Dim tri As New ClsTriangle With {
            .PointA = scaleCenter.Add(scaleCenter.GetVector2dTo(Me.PointA).Multiply(scaleFactor)),
            .PointB = scaleCenter.Add(scaleCenter.GetVector2dTo(Me.PointB).Multiply(scaleFactor)),
            .PointC = scaleCenter.Add(scaleCenter.GetVector2dTo(Me.PointC).Multiply(scaleFactor))
        }

        Return tri
    End Function

    ''' <summary>
    ''' 镜像当前三角形获取新的三角形
    ''' </summary>
    ''' <param name="mirrorP1"></param>
    ''' <param name="mirrorP2"></param>
    ''' <returns></returns>
    Public Function Mirror(ByVal mirrorP1 As ClsPoint2d, ByVal mirrorP2 As ClsPoint2d) As ClsTriangle
        Dim tri As New ClsTriangle With {
            .PointA = Me.PointA.Mirror(mirrorP1, mirrorP2),
            .PointB = Me.PointB.Mirror(mirrorP1, mirrorP2),
            .PointC = Me.PointC.Mirror(mirrorP1, mirrorP2)
        }
        Return tri
    End Function
#End Region

#Region "与cad的三角形转换"
    Public Function CreatefromAcadEntity(pline As Object) As Boolean
        If TypeName(pline) = "IAcadLWPolyline" Then
            Dim tri = pline
            Dim m As New ClsACadObjectEx
            If m.LwPolyLineHasBulge(tri) = False Then
                If UBound(tri.Coordinates) - LBound(tri.Coordinates) = 5 And tri.Closed = True Then
                    Me.PointA = New ClsPoint2d With {.X = tri.Coordinates(0), .Y = tri.Coordinates(1)}
                    Me.PointB = New ClsPoint2d With {.X = tri.Coordinates(2), .Y = tri.Coordinates(3)}
                    Me.PointC = New ClsPoint2d With {.X = tri.Coordinates(4), .Y = tri.Coordinates(5)}
                    Return True
                ElseIf UBound(tri.Coordinates) - LBound(tri.Coordinates) = 7 And tri.Closed = False Then
                    Me.PointA = New ClsPoint2d With {.X = tri.Coordinates(0), .Y = tri.Coordinates(1)}
                    Me.PointB = New ClsPoint2d With {.X = tri.Coordinates(2), .Y = tri.Coordinates(3)}
                    Me.PointC = New ClsPoint2d With {.X = tri.Coordinates(4), .Y = tri.Coordinates(5)}
                    Return True
                Else
                    Return False
                End If
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    Public Function ToAcadEntity(acLayout As Object, Elevation As Double) As Object
        Dim plineAcad As Object
        Dim listVertexs(0 To 7) As Double
        listVertexs(0) = Me.PointA.X : listVertexs(1) = Me.PointA.Y
        listVertexs(2) = Me.PointB.X : listVertexs(3) = Me.PointB.Y
        listVertexs(4) = Me.PointC.X : listVertexs(5) = Me.PointC.Y
        listVertexs(6) = Me.PointA.X : listVertexs(7) = Me.PointA.Y
        plineAcad = acLayout.AddLightWeightPolyline(listVertexs)
        plineAcad.Elevation = Elevation
        Return plineAcad
    End Function
#End Region

End Class


